package com.ztmao.gateway.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ztmao.gateway.config.Config;
import com.ztmao.gateway.dto.GatewayErrorResult;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

@Component
public class TokenValidateGatewayFilterFactory extends AbstractGatewayFilterFactory<Config> {
    private final StringRedisTemplate stringRedisTemplate;
    public TokenValidateGatewayFilterFactory(StringRedisTemplate redisTemplate) {
        super(Config.class);
        this.stringRedisTemplate = redisTemplate;
    }
    @Override
    public GatewayFilter apply(Config config) {

        return ((exchange, chain) -> {
                String requestPath = exchange.getRequest().getURI().getPath();
                String requestMethod = exchange.getRequest().getMethod().name();
                List<String> whitePathList = config.getWhitePathList();
                if(!isPathInWhiteList(requestPath, requestMethod, whitePathList)){
                    String token = exchange.getRequest().getHeaders().getFirst("token");
                    String username = exchange.getRequest().getHeaders().getFirst("username");
                    Object userInfo ;
                    //从redis中获取用户对象信息判断
                    if(StringUtils.hasText(token)&&StringUtils.hasText(username)&&(userInfo = stringRedisTemplate.opsForHash().get("short-link:login:" + username, token)) != null){
                        JSONObject userInfoJsonObject = JSON.parseObject(userInfo.toString());
                        ServerHttpRequest.Builder builder = exchange.getRequest().mutate().headers(httpHeaders -> {
                            httpHeaders.set("userId", userInfoJsonObject.getString("id"));
                            httpHeaders.set("realName", URLEncoder.encode(userInfoJsonObject.getString("realName"), StandardCharsets.UTF_8));
                        });
                        return chain.filter(exchange.mutate().request(builder.build()).build());
                    }
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
                    return response.writeWith(Mono.fromSupplier(() -> {
                        DataBufferFactory bufferFactory = response.bufferFactory();
                        GatewayErrorResult resultMessage = GatewayErrorResult.builder()
                                .status(HttpStatus.UNAUTHORIZED.value())
                                .message("Token validation error")
                                .build();
                        return bufferFactory.wrap(JSON.toJSONString(resultMessage).getBytes());
                    }));
                }
                return chain.filter(exchange);
        });
    }

    private boolean isPathInWhiteList(String requestPath, String requestMethod, List<String> whitePathList) {
        return (!CollectionUtils.isEmpty(whitePathList) && whitePathList.stream().anyMatch(requestPath::startsWith)) || (Objects.equals(requestPath, "/api/short-link/admin/v1/user") && Objects.equals(requestMethod, "POST"));
    }
}
